#pragma once
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include "../../undoRedo/undoRedo.hpp"
#include "../extension/util.hpp"
#include "../layer_ref/models.h"
#include "components.h"
#include "models.h"
#include "qlib/all.h"
namespace qbe::editing::Clipping {
struct PartCheckedInfo {
  std::vector<int> indexs;
  // std::shared_ptr<qlib::Object<T>> graph;
  std::vector<qlib::Vec2d> key_points;
  entt::entity node = entt::null;
  bool is_ellipse = false;
  PartCheckedInfo() {}
  PartCheckedInfo(std::vector<int> _indexs, entt::entity node) : indexs(_indexs), node(node) {}
};

struct ClippingNode {
  entt::entity node;
  std::vector<std::vector<int>> indexes;  //裁切线段的索引
  std::vector<qlib::Vec2d> hit_points;    //和裁切线段的交点
  ClippingNode(entt::entity _node, std::vector<std::vector<int>> _indexes, std::vector<qlib::Vec2d> _hit_points)
      : node(_node), indexes(_indexes), hit_points(_hit_points) {}
};

struct ClippingInfo {
  int line_num;           //裁剪线段的编号0开始
  bool clipping_all;      //裁剪没有交点的线段
  qlib::Vec2d start_pos;  //裁剪线段的起点坐标
  qlib::Vec2d end_pos;    //裁剪线段的终点坐标
  ClippingInfo(int _line_num, bool _clipping_all, qlib::Vec2d _start_pos, qlib::Vec2d _end_pos)
      : line_num(_line_num), clipping_all(_clipping_all), start_pos(_start_pos), end_pos(_end_pos) {}
};

struct SegmentInterInfo {
  int line_num;                          //裁剪线段的编号0开始
  std::vector<qlib::Vec2d> inter_poses;  //相交的坐标
  SegmentInterInfo(int _line_num, std::vector<qlib::Vec2d> _inter_poses) : line_num(_line_num), inter_poses(_inter_poses) {}
};

struct SplitLineInfo {
  bool head_is_inters = false;      //头部是交点
  bool end_is_inters = false;       //尾部是交点
  int start = 0;                    //分解线属于原始线的起始坐标
  int end = 0;                      //分解线属于原始线的终止坐标
  double min_dist = -1;             //最短距离
  bool need_remove = false;         //删除此部分
  std::vector<qlib::Vec2d> points;  //线的顶点
  SplitLineInfo(std::vector<qlib::Vec2d> _points, int _start, int _end, bool _head_is_inters = false, bool _end_is_inters = false)
      : points(_points), start(_start), end(_end), head_is_inters(_head_is_inters), end_is_inters(_end_is_inters) {}
};

struct ClippingData {
  PartCheckedInfo preCheckedEl;
  qlib::Vec2d mouse_pos;
  LayerRef::LayerModel levelparam;
  qlib::Path::s_ptr mouse_line;
  qlib::Cell::s_ptr current_cell;
  double axis_scale;
  layout::LayoutCmd& layout_cmd;
  std::vector<entt::entity> overall_selected_nodes;        //整体选中的对象
  std::vector<PartCheckedInfo> part_selected_nodes;        //部分选中的对象
  std::vector<entt::entity> need_overa_all_checked_datas;  //需要整体选中的对象
  std::vector<PartCheckedInfo> need_part_checked_datas;    //需要部分选中的对象
  std::vector<entt::entity> removes;          //需要删除的对象
  ClippingData(layout::LayoutCmd& _layout_cmd) : layout_cmd(_layout_cmd) {}
};

void clearClippingDisplay(entt::entity& entity, qbe::layout::CellCmd& cmd, layout::CellState& cell_state);

bool isValidClippingNode(qlib::Cell::s_ptr cell, entt::entity el);

bool isValidInsNode(qlib::Cell::s_ptr cell, entt::entity el);

bool arrayAllEqual(const std::vector<qlib::Vec2d>& array);

double distancePointToSegment(const qlib::Vec2d& Q, const qlib::Vec2d& P1, const qlib::Vec2d& P2);

bool lineIntersectsAABB2D(qlib::Vec2d& start, qlib::Vec2d& end, qlib::Vec2d& min, qlib::Vec2d& max);

// 去重并排序函数
std::vector<qlib::Vec2d> uniqueSortedPoints(const std::vector<qlib::Vec2d>& points, const qlib::Vec2d& target);

//寻找要剪掉的部分
std::vector<qlib::Vec2d> findNearestSegment(qlib::Vec2d& start, qlib::Vec2d& end, std::vector<qlib::Vec2d>& all_intersections,
                                            qlib::Vec2d& target_point);

PartCheckedInfo getNearstIntersectEllipse(ClippingData& global, std::vector<entt::entity>& hits, double& min_dist);

PartCheckedInfo getNearstIntersect(ClippingData& global, std::vector<PartCheckedInfo>& hits, double& min_dist);

void getPreClippingData(ClippingData& global, std::vector<PartCheckedInfo>& pre_hits_part);
std::vector<ClippingNode> getPreClippingNodes(ClippingData& global);

bool elementIsSelected(ClippingData& global, ClippingNode& target_node);

bool elementIsPartSelected(ClippingData& global, ClippingNode& target_node);

void getPartCheckedLines(ClippingData& global, ClippingNode& target, std::vector<std::vector<int>>& part_checked_lines);

void getPartCheckedIndexs(ClippingData& global, ClippingNode& target, std::vector<int>& part_checked_indexs);

void intersectWithPath(qlib::Path::s_ptr target_path, qlib::Path::s_ptr path, qlib::Vec2d& start, qlib::Vec2d& end, int start_index, int end_index,
                       std::vector<qlib::Vec2d>& all_intersections, std::vector<int>& sel_indexs);

void intersectWithPolygon(qlib::Polygon::s_ptr polygon, qlib::Vec2d& start, qlib::Vec2d& end, std::vector<qlib::Vec2d>& all_intersections,
                          std::vector<int>& sel_indexs);

void intersectWithKeyPoint(qlib::KeyPoint::s_ptr kp, qlib::Vec2d& start, qlib::Vec2d& end, std::vector<qlib::Vec2d>& all_intersections,
                           std::vector<int>& sel_indexs);

void intersecPolygontWithPolygon(qlib::Polygon::s_ptr target_polygon, qlib::Polygon::s_ptr polygon, qlib::Vec2d& start, qlib::Vec2d& end,
                                 int start_index, int end_index, std::vector<qlib::Vec2d>& all_intersections, std::vector<int>& sel_indexs,
                                 bool is_same);

void intersectWithRefer(qlib::Path::s_ptr target_path, qlib::Reference::s_ptr refer, qlib::Vec2d& start, qlib::Vec2d& end, int start_index,
                        int end_index, std::vector<qlib::Vec2d>& all_intersections);

void intersectPolygonWithRefer(qlib::Polygon::s_ptr target_polygon, qlib::Reference::s_ptr refer, qlib::Vec2d& start, qlib::Vec2d& end,
                               int start_index, int end_index, std::vector<qlib::Vec2d>& all_intersections);

void intersectWithPickedElements(ClippingData& global, qlib::Path::s_ptr target_path, qlib::Vec2d& start, qlib::Vec2d& end, int& start_index,
                                 int& end_index, std::vector<qlib::Vec2d>& all_intersections);

std::vector<entt::entity> getIntersectNodes(ClippingData& global, qlib::Vec2d& start, qlib::Vec2d& end);

void getPathSplitLines(ClippingData& global, qlib::Path::s_ptr target_path, std::vector<qlib::Vec2d>& points, std::vector<SplitLineInfo>& split_lines,
                       std::vector<qlib::Vec2d>& clipping_inters, bool& exist_inter, int index_prefix);

void getPathParCheckedSplitLines(ClippingData& global, qlib::Path::s_ptr target_path, std::vector<qlib::Vec2d>& points,
                                 std::vector<std::vector<int>>& checked_lines_index, std::vector<SplitLineInfo>& split_lines,
                                 std::vector<qlib::Vec2d>& clipping_inters, bool& exist_inter);

void intersectPolygonWithPickedElements(ClippingData& global, entt::entity target_entt, qlib::Polygon::s_ptr target_polygon, qlib::Vec2d& start,
                                        qlib::Vec2d& end, int& start_index, int& end_index, std::vector<qlib::Vec2d>& all_intersections);

void getPolygonPathSplitLines(ClippingData& global, qlib::Polygon::s_ptr target_polygon, std::vector<qlib::Vec2d>& points,
                              std::vector<SplitLineInfo>& split_lines, std::vector<qlib::Vec2d>& clipping_inters, bool& exist_inter,
                              std::vector<int>& real_indexs);

void getPolygonParCheckedSplitLines(ClippingData& global, entt::entity target_entt, qlib::Polygon::s_ptr target_polygon,
                                    std::vector<qlib::Vec2d>& points, std::vector<std::vector<int>>& checked_lines_index,
                                    std::vector<SplitLineInfo>& split_lines, std::vector<qlib::Vec2d>& clipping_inters, bool& exist_inter);

void intersectPolygonWithAll(ClippingData& global, entt::entity target_entt, qlib::Polygon::s_ptr target_polygon, qlib::Vec2d& start,
                             qlib::Vec2d& end, int& start_index, int& end_index, std::vector<qlib::Vec2d>& all_intersections);

void getPolygonSplitLines(ClippingData& global, entt::entity target_entt, qlib::Polygon::s_ptr target_polygon, std::vector<qlib::Vec2d>& points,
                          std::vector<SplitLineInfo>& split_lines, std::vector<qlib::Vec2d>& clipping_inters, bool& exist_inter, bool insert_all);
double getLineDistWithPoint(const std::vector<qlib::Vec2d>& points, qlib::Vec2d& target_point);

std::vector<qlib::Vec2d> getClippingLineWithTarget(std::vector<SplitLineInfo>& split_lines, qlib::Vec2d& target_point);

std::vector<std::vector<int>> getElementPartSelectIndexs(ClippingData& global, entt::entity target);

void intersectWithAll(ClippingData& global, qlib::Path::s_ptr target_path, qlib::Vec2d& start, qlib::Vec2d& end, int& start_index, int& end_index,
                      std::vector<qlib::Vec2d>& all_intersections);

std::vector<std::vector<int>> getSplitLinePartCheckedIndexs(int start_index, int end_index, std::vector<std::vector<int>>& part_checked_lines);

std::vector<std::vector<int>> getPolygonSplitLinePartCheckedIndexs(int start_index, int end_index, std::vector<std::vector<int>>& part_checked_lines,
                                                                   int point_size);

void clearNodeCheckedData(ClippingData& global, entt::entity node);

void doClippingPath(ClippingData& global, ClippingNode& clipping_node, qlib::Path::s_ptr path_node, std::vector<ClippingInfo>& clipping_data,
                    undoRedoT::UndoRedoModule& undoRedoModule);
std::vector<qlib::Vec2d> getPathValidPoints(std::vector<qlib::Vec2d>& points);

void clippingPolygonWithTarget(ClippingData& global, ClippingNode& clipping_node, qlib::Polygon::s_ptr polygon_node,
                               std::vector<SplitLineInfo>& split_lines, bool remove_all, std::vector<std::vector<int>> part_checked_lines,
                               int points_size, undoRedoT::UndoRedoModule& undoRedoModule);

//裁剪多边形
void clippingPolygonByData(ClippingData& global, ClippingNode& clipping_node, qlib::Polygon::s_ptr polygon_node,
                           std::vector<ClippingInfo>& clipping_data, bool& is_elippse, undoRedoT::UndoRedoModule& undoRedoModule);

void doClippingPathWithTarget(ClippingData& global, ClippingNode& clipping_node, qlib::Path::s_ptr path_node, std::vector<SplitLineInfo>& split_lines,
                              bool remove_all, std::vector<std::vector<int>>& part_checked_lines, std::vector<int>& part_check_indxs,
                              undoRedoT::UndoRedoModule& undoRedoModule);

void doClippingLine(ClippingData& global, ClippingNode clipping_node, qlib::Path::s_ptr path_node, std::vector<std::vector<int>>& picked_lines_index,
                    std::vector<qlib::Vec2d>& hit_points, std::vector<qlib::Vec2d>& clipping_inters,
                    std::vector<std::vector<qlib::Vec2d>>& clipping_display_lines, bool& data_changed, bool process_extend,
                    undoRedoT::UndoRedoModule& undoRedoModule);

void doClippingPolygon(ClippingData& global, ClippingNode clipping_node, qlib::Polygon::s_ptr target_polygon,
                       std::vector<std::vector<int>>& picked_lines_index, std::vector<qlib::Vec2d>& hit_points,
                       std::vector<qlib::Vec2d>& clipping_inters, std::vector<std::vector<qlib::Vec2d>>& clipping_display_lines, bool& data_changed,
                       bool process_clipping, undoRedoT::UndoRedoModule& undoRedoModule);

//更新左下角信息
void updateClippingStatusBarInfo(ecs::Bus& bus, bool picked_lines, bool exist_clipping_lines, bool exist = false);

bool elementIsVisible(long layer_num);

bool arePointsEqual(qlib::Vec2d a, qlib::Vec2d b);
}  // namespace qbe::editing::Clipping